home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 September / PCWorld_2008-09_cd.bin / v cisle / sadanastroju / bookmark_previews-0.6.5-fx.xpi / chrome / content / managerOverlay.js < prev    next >
Text File  |  2008-05-27  |  33KB  |  792 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is the Bookmark Previews extension.
  15.  *
  16.  * The Initial Developer of the Original Code is
  17.  * John Marshall <JohnM555@gmail.com>.
  18.  * Portions created by the Initial Developer are Copyright (C) 2007
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *   John Marshall <JohnM555@gmail.com>
  23.  *
  24.  * Alternatively, the contents of this file may be used under the terms of
  25.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  26.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27.  * in which case the provisions of the GPL or the LGPL are applicable instead
  28.  * of those above. If you wish to allow use of your version of this file only
  29.  * under the terms of either the GPL or the LGPL, and not to allow others to
  30.  * use your version of this file under the terms of the MPL, indicate your
  31.  * decision by deleting the provisions above and replace them with the notice
  32.  * and other provisions required by the GPL or the LGPL. If you do not delete
  33.  * the provisions above, a recipient may use your version of this file under
  34.  * the terms of any one of the MPL, the GPL or the LGPL.
  35.  *
  36.  * ***** END LICENSE BLOCK ***** */
  37.  
  38. if (!("Ci" in window)){
  39.   Ci = Components.interfaces;
  40.   Cc = Components.classes;
  41. }
  42. var ThumbView = null;
  43. var PreviewImages = {
  44.   folder : {
  45.     url: "chrome://bookmarkpreviews/skin/folder.png",
  46.     image: null
  47.   },
  48.   nopreview : {
  49.     url: "chrome://bookmarkpreviews/skin/nopreview.png",
  50.     image: null
  51.   }
  52. }
  53.  
  54. var BookmarksPreviewUtils = {
  55.   utils : null,
  56.   displayRoot : null,
  57.   location : null,
  58.   contentDeck : null,
  59.   selected : null,
  60.   dir : null,
  61.   bkmksTree : null,
  62.   placesTree : null,
  63.   _history : [],
  64.   _historyIndex : 0,
  65.   init : function(){
  66.     try{
  67.     //dump("init\n");
  68.     var self = BookmarksPreviewUtils;
  69.     BookmarksPreviewUtils.dir = Components.classes["@mozilla.org/file/directory_service;1"]
  70.                      .getService(Components.interfaces.nsIProperties)
  71.                      .get("ProfD", Components.interfaces.nsIFile);
  72.     BookmarksPreviewUtils.dir.append("bookmarkpreviews");
  73.     if (!BookmarksPreviewUtils.dir.exists())
  74.       BookmarksPreviewUtils.dir.create(Components.interfaces.nsIFile.DIRECTORY_TYPE,0777);
  75.  
  76.     self.placesTree = document.getElementById("bookmark-folders-view");
  77.     var folderWidth = self.placesTree.getAttribute("width");
  78.     /* since some lovely person decided, 'Hey, we don't need to include ids
  79.       in order to make it easier for extension developers to overlay the
  80.       bookmarks manager' these elements need to be added & positioned with
  81.       javascript. Yay! */
  82.     var vbox = document.createElement("vbox");
  83.     vbox.setAttribute("id","defaultView");
  84.     self.bkmksTree = document.getElementById("bookmarks-view");
  85.     var bkmksWidth = self.bkmksTree.boxObject.width;//document.documentElement.boxObject.width - self.placesTree.width;//self.bkmksTree.boxObject.width
  86.     var container = document.getElementById("albumview-container");
  87.     container = container.parentNode.removeChild(container);
  88.     vbox.appendChild(container);
  89.     var splitter = document.createElement("splitter");
  90.     var grippy = document.createElement("grippy");
  91.     splitter.appendChild(grippy);
  92.     splitter.setAttribute("id","albumview-splitter");
  93.     splitter.setAttribute("oncommand","BookmarksPreviewUtils.onResize(event);");
  94.     vbox.appendChild(splitter);
  95.  
  96.     var deck = document.createElement("deck");
  97.     //var deck = document.createElement("vbox");
  98.     deck.setAttribute("id","contentDeck");
  99.     deck.setAttribute("persist","width");
  100.     deck.setAttribute("flex","4");
  101.     deck.appendChild(vbox);
  102.     self.bkmksTree.parentNode.insertBefore(deck,self.bkmksTree);
  103.  
  104.     /* Since xbl kills babies(bug 50349) the destructor isn't called when this
  105.       is removed, although the constructor is called when it is re-added. That
  106.       means the transaction listener and other observers get added twice.
  107.       Not good.... So remove it before we (re)move the element.
  108.       This prevents leaking.
  109.     */
  110.     self._bkmksTreeDestructor(self.bkmksTree);
  111.     self.bkmksTree.parentNode.removeChild(self.bkmksTree);
  112.     vbox.appendChild(self.bkmksTree);
  113.  
  114.     self.bkmksTree.treeBuilder.addObserver(BookmarksPreviewUtils);
  115.     //bmFolderView.treeBuilder.addObserver(BookmarksPreviewUtils);
  116.     /* Listen to when ref changes instead of the left tree's select
  117.       observer because we also want to be notified when a search has
  118.       been performed
  119.     */
  120.     self.bkmksTree.addEventListener("DOMAttrModified",self.refModified,false);
  121.     /* set the folder tree back to its original size. After we remove the bkmks tree
  122.     (so we can insert it into the deck) the folders tree expands because its flex is 1.*/
  123.     //setTimeout(function(){
  124.       //self.placesTree.setAttribute("width",folderWidth);
  125.       //deck.setAttribute("width",bkmksWidth);
  126.     //},11);
  127.  
  128.     /* Once again, because this window was designed to be soo extensible, I need to
  129.       add any new menu items in through here instead of with a nice, quick, xul overlay */
  130.     var export_menuitem = document.getElementsByAttribute("command","cmd_bm_export")[0];
  131.     var create_menuitem = document.getElementById("create_previews");
  132.     export_menuitem.parentNode.insertBefore(create_menuitem,export_menuitem.nextSibling);
  133.  
  134.     /* create new menu items in the view menu */
  135.     var nextElement = curElement = document.getElementById("view-separator");
  136.     var insertbefore = document.getElementById("fill-after-this-node");
  137.     var viewMenu = insertbefore.parentNode;
  138.     var addItems = true;
  139.     while(addItems){
  140.       nextElement = curElement.nextSibling;
  141.       addItems = curElement.id!="thumbsSize";
  142.       viewMenu.insertBefore(curElement,insertbefore);
  143.       curElement = nextElement;
  144.     }
  145.  
  146.     /* Insert thumnail view in the correct spot */
  147.     //ThumbView = document.getElementById("thumbnailView");
  148.     //ThumbView = ThumbView.parentNode.removeChild(ThumbView);
  149.     ThumbView = document.createElement("thumbnailview");
  150.     ThumbView.setAttribute("id","thumbnailView");
  151.     ThumbView = deck.appendChild(ThumbView);
  152.     //dump("thumbview: "+ThumbView+"\n");
  153.  
  154.     splitter = document.getElementById("bookmark-views-splitter");
  155.     splitter.setAttribute("oncommand","BookmarksPreviewUtils.onResize(event);");
  156.  
  157.     const kPrefSvcContractID = "@mozilla.org/preferences-service;1";
  158.     const kPrefSvcIID = Components.interfaces.nsIPrefService;
  159.     var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
  160.     var prefs = prefSvc.getBranch(null);
  161.     const kPrefBranchInternalIID = Components.interfaces.nsIPrefBranch2;
  162.     var bookmarksPrefsInternal = prefs.QueryInterface(kPrefBranchInternalIID);
  163.     bookmarksPrefsInternal.addObserver(self.sortChangedObserver.domain,
  164.                                        self.sortChangedObserver, false);
  165.  
  166.     BookmarksPreviewUtils.contentDeck = deck;
  167.     var detailsMenu = document.getElementById("detailsViewMenu");
  168.     if (detailsMenu.getAttribute("checked"))
  169.       BookmarksPreviewUtils.onSelectView('details');
  170.     else{
  171.       var thumbsMenu = detailsMenu.nextSibling;
  172.       if (!thumbsMenu.getAttribute("checked"))
  173.         BookmarksPreviewUtils.onSelectView('details');
  174.       else
  175.         BookmarksPreviewUtils.onSelectView('thumbnails');
  176.     }
  177.     // Adding the transaction listener
  178.     var bkmkTxnSvc = Components.classes["@mozilla.org/bookmarks/transactionmanager;1"]
  179.                               .getService(Components.interfaces.nsIBookmarkTransactionManager);
  180.     bkmkTxnSvc.transactionManager.AddListener(self);
  181.     BMDS.AddObserver(self);
  182.     window.addEventListener("resize",self.onResize,false);
  183.     /* Listen for when the previews get updated */
  184.     var observerService = Components.classes["@mozilla.org/observer-service;1"]
  185.                           .getService(Components.interfaces.nsIObserverService);
  186.     observerService.addObserver(self, "bookmarkpreviews:preview-updated", false);
  187.  
  188.     setTimeout(function(){
  189.       self.bkmksTree.focus();
  190.       self.bkmksTree.tree.view.selection.select(0);
  191.     },0);
  192.     }catch(e){Components.utils.reportError(e);}
  193.   },
  194.   _bkmksTreeDestructor : function(aBkmksTree){
  195.     var bkmkTxnSvc = Components.classes["@mozilla.org/bookmarks/transactionmanager;1"]
  196.                       .getService(Components.interfaces.nsIBookmarkTransactionManager);
  197.     bkmkTxnSvc.transactionManager.RemoveListener(aBkmksTree.bookmarkTreeTransactionListener);
  198.     aBkmksTree.treeBuilder.removeObserver(aBkmksTree.builderObserver);
  199.     aBkmksTree.tree.controllers.removeController(aBkmksTree.controller);
  200.     // Unhook the sort change observer for this tree
  201.     const kPrefSvcContractID = "@mozilla.org/preferences-service;1";
  202.     const kPrefSvcIID = Components.interfaces.nsIPrefService;
  203.     var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
  204.     var prefs = prefSvc.getBranch(null);
  205.     const kPrefBranchInternalIID = Components.interfaces.nsIPrefBranch2;
  206.     var bookmarksPrefsInternal = prefs.QueryInterface(kPrefBranchInternalIID);
  207.     bookmarksPrefsInternal.removeObserver(aBkmksTree.sortChangedObserver.domain,
  208.                                           aBkmksTree.sortChangedObserver);
  209.   },
  210.   uninit : function(){
  211.     var self = BookmarksPreviewUtils;
  212.     self.bkmksTree.treeBuilder.removeObserver(BookmarksPreviewUtils);
  213.     self.bkmksTree.removeEventListener("DOMAttrModified",self.refModified,false);
  214.     window.removeEventListener("resize",self.onResize,false);
  215.     // Unhook the sort change observer
  216.     const kPrefSvcContractID = "@mozilla.org/preferences-service;1";
  217.     const kPrefSvcIID = Components.interfaces.nsIPrefService;
  218.     var prefSvc = Components.classes[kPrefSvcContractID].getService(kPrefSvcIID);
  219.     var prefs = prefSvc.getBranch(null);
  220.     const kPrefBranchInternalIID = Components.interfaces.nsIPrefBranch2;
  221.     var bookmarksPrefsInternal = prefs.QueryInterface(kPrefBranchInternalIID);
  222.     bookmarksPrefsInternal.removeObserver(self.sortChangedObserver.domain,
  223.                                           self.sortChangedObserver);
  224.     var bkmkTxnSvc = Components.classes["@mozilla.org/bookmarks/transactionmanager;1"]
  225.                               .getService(Components.interfaces.nsIBookmarkTransactionManager);
  226.     bkmkTxnSvc.transactionManager.RemoveListener(self);
  227.     BMDS.RemoveObserver(self)
  228.     var observerService = Components.classes["@mozilla.org/observer-service;1"]
  229.                             .getService(Components.interfaces.nsIObserverService);
  230.     observerService.removeObserver(self, "bookmarkpreviews:preview-updated");
  231.     if (ThumbView.initiated)
  232.       ThumbView.uninit();
  233.     if (AlbumView.initiated)
  234.       AlbumView.uninit();
  235.   },
  236.   onResize : function(event){
  237.     BookmarksPreviewUtils.utils.onResize(event);
  238.   },
  239.   refModified : function(event){
  240.     if (event.attrName=="ref" && event.target == BookmarksPreviewUtils.bkmksTree
  241.         && !BookmarksPreviewUtils.utils.updatedSelection){
  242.       //dump("ref modified\n");
  243.       BookmarksPreviewUtils.utils.refreshDisplay();
  244.     }
  245.   },
  246.   sortChangedObserver : {
  247.     domain: "browser.bookmarks.sort",
  248.     _isSorted : null,
  249.     /*
  250.        What were these people thinking? I must be missing something obvious
  251.        because apparently if the tree is unsorted(aka natural), the direction
  252.        is descending, when the tree is ascending, the direction is natural,
  253.        and when the tree is descending, the direction is ascending.
  254.        How does that make sense?!
  255.  
  256.        So instead of logically check that the current direction is not "natural",
  257.        which most people in this context would take to mean unsorted, we need to
  258.        make sure the direction is not "descending". Duh.
  259.     */
  260.     get isSorted(){
  261.       if (this._isSorted == null){
  262.         var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
  263.         var prefs = prefSvc.getBranch(this.domain+".");
  264.         this._isSorted = prefs.getCharPref("direction") != "descending";
  265.       }
  266.       return this._isSorted;
  267.     },
  268.     observe: function BMU_sortChangedObserver(aSubject, aTopic, aPrefName) {
  269.       if (aTopic != "nsPref:changed") return;
  270.       if (aPrefName.substr(0, this.domain.length) != this.domain) return;
  271.       //dump("sort changed\n");
  272.  
  273.       var prefSvc = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService);
  274.       var prefs = prefSvc.getBranch(this.domain+".");
  275.       this._isSorted = prefs.getCharPref("direction") != "descending";
  276.       //dump("sort direction: "+prefs.getCharPref("direction")+"\n");
  277.  
  278.       setTimeout(function(){
  279.         /* this is called before the tree ends up getting sorted, which we need because
  280.           we take the results directly from the tree's view. setTimeout fixes it.
  281.         */
  282.         BookmarksPreviewUtils.utils.refreshDisplay(true);//.refreshSort();
  283.       },0);
  284.     }
  285.   },
  286.   onSelectView : function(type,event){
  287.     //dump("type: "+type+"\n");
  288.     var self = BookmarksPreviewUtils;
  289.     self.selected = type;
  290.     if (type=="details"){
  291.       if (!event || self.contentDeck.selectedIndex!=0){
  292.         self.contentDeck.selectedIndex=0;
  293.         if (ThumbViewUtils.initiated){
  294.           ThumbViewUtils.uninit();
  295.         }
  296.         AlbumViewUtils.initDisplay();
  297.       }
  298.     } else if (type=="thumbnails"){
  299.       if (!event || self.contentDeck.selectedIndex!=1){
  300.         self.contentDeck.selectedIndex=1;
  301.         if (AlbumView.initiated){
  302.           AlbumView.uninit();
  303.           ThumbViewUtils.initDisplay();
  304.         }
  305.         else{/* first load, give time for the contents to get set up */
  306.           setTimeout(function(){ThumbViewUtils.initDisplay();},0);
  307.         }
  308.       }
  309.     }
  310.   },
  311.   getViewRoot : function(aCurIndex, aRootIndex){
  312.     var root;
  313.     var curIndex = BookmarksPreviewUtils.bkmksTree.currentIndex;
  314.     var rootIndex = -1;
  315.     if (curIndex>-1 && BookmarksPreviewUtils.bkmksTree.tree.view.isContainer(curIndex))
  316.       rootIndex = curIndex;
  317.     else if (curIndex>-1)
  318.       rootIndex = BookmarksPreviewUtils.bkmksTree.tree.view.getParentIndex(curIndex);;
  319.     if (rootIndex>-1)
  320.       root = BookmarksPreviewUtils.bkmksTree.getRowResource(rootIndex);
  321.     else{
  322.       root = BookmarksPreviewUtils.bkmksTree.getRootResource();
  323.     }
  324.     if (BookmarksPreviewUtils.displayRoot != root){
  325.       BookmarksPreviewUtils.addToBackHistory(root,"utils");
  326.       BookmarksPreviewUtils.displayRoot = root;
  327.     }
  328.     if (aCurIndex)
  329.       aCurIndex.value = curIndex;
  330.     if (aRootIndex)
  331.       aRootIndex.value = rootIndex;
  332.     return root;
  333.   },
  334.   getBookmarkImages : function(bkmks,folder){
  335.     if (!folder)
  336.       folder = BookmarksPreviewUtils.getViewRoot();
  337.     var self = BookmarksPreviewUtils;
  338.     var idx = self.bkmksTree.treeBuilder.getIndexOfResource(folder);
  339.     var view = self.bkmksTree.tree.view;
  340.     var urlCol = self.bkmksTree.tree.columns.getNamedColumn("URL");
  341.     var nameCol = self.bkmksTree.tree.columns.getNamedColumn("Name");
  342.     var rowCount = view.rowCount;
  343.     if (rowCount>0){
  344.       var isOpen = idx==-1 || view.isContainerOpen(idx);
  345.       if (!isOpen) {
  346.         view.toggleOpenState(idx);
  347.         rowCount = view.rowCount;
  348.       }
  349.       var level = view.getLevel(idx+1);
  350.       var containerLevel = idx>-1?view.getLevel(idx):-1;
  351.       if (level > containerLevel){
  352.         for (var i = idx+1; i<rowCount; i++){
  353.           var rowLevel = view.getLevel(i);
  354.           if (rowLevel==level){
  355.             var resource = self.bkmksTree.getRowResource(i);
  356.             if (resource instanceof Components.interfaces.nsIRDFResource){
  357.               var aType = BookmarksUtils.resolveType(resource);
  358.               if (aType!="BookmarkSeparator"){
  359.                 var url = null;
  360.                 if (!view.isContainer(i))
  361.                   url = view.getCellText(i,urlCol);
  362.                 var name = view.getCellText(i,nameCol);
  363.                 var image = BookmarksPreviewUtils._getResourceImage(aType,url);
  364.                 bkmks.push({image: image,
  365.                             caption: name && name.length>0?name:url,
  366.                             url: url,
  367.                             node: resource});
  368.               }
  369.             }
  370.           }
  371.           else if (rowLevel<level){
  372.             break;
  373.           }
  374.         }
  375.       }
  376.       if (!isOpen) view.toggleOpenState(idx);
  377.     }
  378.   },
  379.   _getResourceImage : function(aType,aURL){
  380.     var folderImage = "chrome://bookmarkpreviews/skin/folder.png";
  381.     if (aType == "Livemark" || aType == "Folder" || aType=="PersonalToolbarFolder"){
  382.       return folderImage;
  383.     }
  384.     return this.getImageForURL(aURL);
  385.   },
  386.   getImageForURL : function(aURL){
  387.     var nopreview = "chrome://bookmarkpreviews/skin/nopreview.png";
  388.     if (aURL){
  389.       var file = PreviewServiceUtils.getPreviewFile(aURL,this.dir);
  390.       if (file.exists() && file.isFile()){
  391.         var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
  392.         var uri = ios.newFileURI(file);
  393.         if (uri)
  394.           return uri.spec;
  395.       }
  396.     }
  397.     return nopreview;
  398.   },
  399.   addToBackHistory : function(resource,from){
  400.     if (!this._history.some(function(ele,idx){
  401.           return ele.Value == resource.Value;
  402.         })){
  403.       this._history.splice(0,this._historyIndex==0?0:this._historyIndex,resource);
  404.       this._historyIndex = 0;
  405.     }
  406.     this.updateNavigationStates();
  407.   },
  408.   back : function(event){
  409.     this.navigateHistory(1);
  410.   },
  411.   forward : function(event){
  412.     this.navigateHistory(-1);
  413.   },
  414.   navigateHistory : function(direction){
  415.     var location = this.getViewRoot();
  416.     this._historyIndex+=direction;
  417.     var historyEntry = this._history[this._historyIndex];
  418.     BookmarksPreviewUtils.utils.updatedSelection = true;
  419.     //var parent = BMDS.getParent(resource);
  420.     if (historyEntry.Value=="NC:BookmarksTopRoot"){
  421.       this.bkmksTree.tree.ref=historyEntry.Value;
  422.       this.bkmksTree.tree.view.selection.clearSelection();
  423.       this.bkmksTree.tree.view.selection.currentIndex=-1;
  424.     }
  425.     else{
  426.       this.placesTree.tree.view.selection.clearSelection();
  427.       this.placesTree.selectResource(historyEntry);
  428.       var parent = BMDS.getParent(historyEntry);
  429.       this.bkmksTree.tree.ref=parent.Value;
  430.       this.bkmksTree.tree.view.selection.clearSelection();
  431.       this.bkmksTree.selectResource(historyEntry);
  432.     }
  433.     BookmarksPreviewUtils.utils.updatedSelection = false;
  434.     this.placesTree.treeBoxObject.ensureRowIsVisible(
  435.       this.placesTree.treeBuilder.getIndexOfResource(historyEntry));
  436.     BookmarksPreviewUtils.utils.refreshDisplay();
  437.     this.updateNavigationStates();
  438.   },
  439.   updateNavigationStates : function(){
  440.     var backbutton = document.getElementById("back-button");
  441.     if (this._historyIndex==this._history.length-1 ){
  442.       backbutton.setAttribute("disabled","true");
  443.     }
  444.     else
  445.       backbutton.removeAttribute("disabled");
  446.     var forwardbutton = document.getElementById("forward-button");
  447.     if (this._historyIndex==0 ){
  448.       forwardbutton.setAttribute("disabled","true");
  449.     }
  450.     else
  451.       forwardbutton.removeAttribute("disabled");
  452.   },
  453.   canDrop : function(index, orientation){},
  454.   onDrop : function(row, orientation){},
  455.   onToggleOpenState  : function(index){},
  456.   onCycleHeader : function(column){},
  457.   onCycleCell : function(row, column){},
  458.   onSelectionChanged : function(){
  459.     //dump("selection changed - "+AlbumView.updatedSelection+" - \n");
  460.     if (!BookmarksPreviewUtils.utils.updatedSelection)
  461.       /*
  462.       This listens to the detailed view and the folder view.
  463.       Although the selection of the detailed view is updated in time when
  464.       this is sent from the detailed view's tree, it isn't updated
  465.       in time when it is sent from a selection change from the folder
  466.       view so we need to use setTimeout.
  467.       */
  468.  
  469.       setTimeout(function(){
  470.         //dump("selection changed - tree observer\n");
  471.         BookmarksPreviewUtils.utils.refreshDisplay();
  472.       },0);
  473.   },
  474.   onPerformAction : function(action){},
  475.   onPerformActionOnRow : function(action, row){},
  476.   onPerformActionOnCell : function(action, row, column){},
  477.   _lastTransactionItem : null,
  478.   observeTransaction : function(aTxn, aDo){
  479.     //dump("observer transaction: "+aTxn+"|"+aDo+"\n");
  480.     if (!aTxn) return;
  481.     aTxn = aTxn.wrappedJSObject;
  482.     //dump("aTxn: "+aTxn+"\n");
  483.     var item = aTxn.item;
  484.     this._lastTransactionItem = item;
  485.  
  486.     if (this.utils.updatedSelection) return;
  487.  
  488.     var type = aTxn.type;
  489.     var itemType = BookmarksUtils.resolveType(item);
  490.     if (itemType != "BookmarkSeparator"){
  491.       var parent = aTxn.parent;
  492.       if (parent == this.displayRoot){
  493.         this.utils.refreshDisplay(true);
  494.       }
  495.     }
  496.   },
  497.   /* Transaction Listener */
  498.   willDo: function (aTxmgr, aTxn) {},
  499.   didDo : function (aTxmgr, aTxn) {
  500.     this.observeTransaction(aTxn, true);
  501.   },
  502.   willUndo: function (aTxmgr, aTxn) {},
  503.   didUndo : function (aTxmgr, aTxn) {
  504.     this.observeTransaction(aTxn, false);
  505.   },
  506.   willRedo: function (aTxmgr, aTxn) {},
  507.   didRedo : function (aTxmgr, aTxn) {
  508.     this.observeTransaction(aTxn, true);
  509.   },
  510.   didMerge       : function (aTxmgr, aTxn) {},
  511.   didBeginBatch  : function (aTxmgr, aTxn) {},
  512.   didEndBatch    : function (aTxmgr, aTxn) {
  513.     this.observeTransaction(aTxn, this.mLastTxnWasDo);
  514.   },
  515.   willMerge      : function (aTxmgr, aTxn) {},
  516.   willBeginBatch : function (aTxmgr, aTxn) {},
  517.   willEndBatch   : function (aTxmgr, aTxn) {},
  518.   /* nsIRDFObserver
  519.     the transaction manager takes care of everything but when bookmarks
  520.     change, so we need the onChange here
  521.   */
  522.   onAssert            : function(ds, source, predicate, target){},
  523.   onUnassert          : function(ds, source, predicate, target){},
  524.   onChange            : function(ds, source, predicate, oldTarget, newTarget){
  525.     if (predicate.Value == "http://home.netscape.com/NC-rdf#Name"){
  526.       //dump("onChange = source: "+source+" oldTarget: "+oldTarget.Value+" newTarget: "+newTarget.Value+"\n");
  527.       var oldVal, newVal;
  528.       if (oldTarget instanceof Components.interfaces.nsIRDFLiteral)
  529.         oldVal = oldTarget.Value;
  530.       if (newTarget instanceof Components.interfaces.nsIRDFLiteral)
  531.         newVal = newTarget.Value;
  532.       //dump("old|new val: "+oldVal+"|"+newVal+"\n");
  533.       this.utils.updateNodeTitle(source,oldVal,newVal);
  534.     }
  535.   },
  536.   onMove              : function(ds, oldSource, newSource, predicate, target){},
  537.   onBeginUpdateBatch  : function(ds){},
  538.   onEndUpdateBatch    : function(ds){},
  539.   /* nsIObserver */
  540.   observe: function(subject, topic, data) {
  541.     if (topic == "bookmarkpreviews:preview-updated"){
  542.       /* subject = updated uri */
  543.       this.utils.updatePreview(subject);
  544.     }
  545.   },
  546.   createPreviews : function(){
  547.     var strbundleService = Components.classes ["@mozilla.org/intl/stringbundle;1"]
  548.                         .getService(Components.interfaces.nsIStringBundleService);
  549.     var bundle = strbundleService.createBundle("chrome://bookmarkpreviews/locale/strings.properties");
  550.     var dialogQ = bundle.GetStringFromName("createpreviewsmessage");
  551.     var dialogTitle = bundle.GetStringFromName("createpreviewsdialogtitle");
  552.     var prompts = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
  553.                         .getService(Components.interfaces.nsIPromptService);
  554.     var result = prompts.confirm(window, dialogTitle, dialogQ);
  555.     if (result){
  556.       var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  557.                        .getService(Components.interfaces.nsIWindowMediator);
  558.       var newWindow = wm.getMostRecentWindow("navigator:browser");
  559.       if (newWindow)
  560.         newWindow.PreviewService.generateAllPreviews();
  561.       //XXX do something if there is no preview window...
  562.     }
  563.   }
  564. }
  565. var AlbumViewUtils = {
  566.   all : null,
  567.   bkmksTree : null,
  568.   tree : null,
  569.   view : null,
  570.   get bkmksTree(){
  571.     return BookmarksPreviewUtils.bkmksTree;
  572.   },
  573.   get displayRoot(){
  574.     return BookmarksPreviewUtils.displayRoot;
  575.   },
  576.   set displayRoot(val){
  577.     BookmarksPreviewUtils.displayRoot = val;
  578.   },
  579.   initDisplay : function(){
  580.     BookmarksPreviewUtils.utils = AlbumViewUtils;
  581.     AlbumViewUtils.tree = BookmarksPreviewUtils.bkmksTree.tree;
  582.     AlbumViewUtils.view = BookmarksPreviewUtils.bkmksTree.tree.view;
  583.     AlbumView.init();
  584.     setTimeout(AlbumViewUtils.refreshDisplay,0);
  585.   },
  586.   uninit : function(){
  587.  
  588.   },
  589.   onResize : function(event){
  590.     if (AlbumView.canRefresh){
  591.       var orient = 1;
  592.       if (event.target.id == "bookmark-views-splitter")
  593.         orient = 0;//Horizontal
  594.       AlbumView.refresh(orient);
  595.       /* When dragging the horizontal splitter up the canvas
  596.       paints on to the headers of the tree. This will refresh
  597.       some of the labels, but it doesn't do the greatest job.
  598.       I'm not sure how to force a repaint of an xul element*/
  599.       var col = BookmarksPreviewUtils.bkmksTree.treeBoxObject.columns.getFirstColumn().element;
  600.       while (col){
  601.         col.setAttribute("crop","end");
  602.         col.setAttribute("crop","none");
  603.         col = col.nextSibling;
  604.       }
  605.     }
  606.   },
  607.   refreshDisplay : function(aForceRefresh){
  608.     try{
  609. //    //dump("refresh album display: "+aForceRefresh+"\n");
  610.       var curIndexObj = new Object(), rootIndexObj = new Object();
  611.       var previousRoot = AlbumViewUtils.displayRoot;
  612.       var root = BookmarksPreviewUtils.getViewRoot(curIndexObj, rootIndexObj);
  613.       var curIndex = curIndexObj.value, rootIndex = rootIndexObj.value;
  614.       if (aForceRefresh || root!=previousRoot){
  615.         var bkmks=[]
  616.         BookmarksPreviewUtils.getBookmarkImages(bkmks,root);
  617.         AlbumView.createImages(bkmks);
  618.         AlbumView.current = AlbumView.target = 0;
  619.       }
  620.       var nextTarget=AlbumViewUtils._getNextTarget(curIndex,rootIndex);
  621.       AlbumView.keepFocus = false;
  622.       AlbumView.refresh(-1);
  623.       if (!(curIndex>-1 && AlbumViewUtils.view.isSeparator(curIndex)))
  624.         AlbumView.glideTo(nextTarget*-150,false);
  625.     }catch(e){
  626.       Components.utils.reportError("AUTILS: "+e);
  627.     }
  628.   },
  629.   _getNextTarget : function(cIndex,rIndex){
  630.     if (cIndex>rIndex+1){
  631.       var max = AlbumViewUtils.view.rowCount, level = AlbumViewUtils.view.getLevel(cIndex);
  632.       var nextTarget = 0;//rIndex==-1?-1:0;
  633.       for (var i = rIndex+1;i<cIndex;i++){
  634.         if (AlbumViewUtils.view.getLevel(i)==level &&
  635.            !AlbumViewUtils.view.isSeparator(i))
  636.           nextTarget++;
  637.       }
  638.       return nextTarget;
  639.     }
  640.     return 0;
  641.   },
  642.   updatePreview : function(aURI){
  643.     aURI = aURI.QueryInterface(Components.interfaces.nsIURI);
  644.     for (var i = 0; i < AlbumView.max; i++){
  645.       var url = AlbumView.itemProps[i].url;
  646.       if (url == aURI.spec){
  647.         var imgsrc = BookmarksPreviewUtils.getImageForURL(url);
  648.         AlbumView.itemImages[i]=null;
  649.         AlbumView.itemImages[i]=new Image();
  650.         let x = i;
  651.         AlbumView.itemImages[i].onload = function preview_load(){
  652.           AlbumView.imageLoaded(x);
  653.         }
  654.         AlbumView.itemImages[i].src = imgsrc;
  655.         if (AlbumView.itemImages[i].complete){
  656.           AlbumView.imageLoaded(i);
  657.         }
  658.         break;
  659.       }
  660.     }
  661.   },
  662.   updateNodeTitle : function(aNode, aPrevVal, aNewVal){
  663.     for (var i = 0; i < AlbumView.max; i++){
  664.       var node = AlbumView.itemProps[i].node;
  665.       if (node == aNode){
  666.         AlbumView.itemProps[i].caption = aNewVal;
  667.         AlbumView.caption.value = aNewVal;
  668.         break;
  669.       }
  670.     }
  671.   },
  672.   selectIndex : function(resource){
  673.     if (AlbumView.keepFocus){
  674.       AlbumViewUtils.updatedSelection = true;
  675.       AlbumViewUtils.view.selection.clearSelection();
  676.       AlbumViewUtils.bkmksTree.selectResource(resource);
  677.       AlbumViewUtils.bkmksTree.treeBoxObject.ensureRowIsVisible(
  678.           AlbumViewUtils.bkmksTree.treeBuilder.getIndexOfResource(resource));
  679.       AlbumViewUtils.updatedSelection = false;
  680.       //setTimeout(function(){AlbumViewUtils.container.focus();},0);
  681.     }
  682.     AlbumView.keepFocus = true;
  683.   },
  684.   performAction : function(resource,event){
  685.     //dump("albumviewutils.performaction: "+resource+"|"+event);
  686.     var aType = BookmarksUtils.resolveType(resource);
  687.     if (aType == "Bookmark"){
  688.       var target = BMDS.GetTarget(resource, RDF.GetResource("http://home.netscape.com/NC-rdf#URL"), true);
  689.       target = target.QueryInterface(Components.interfaces.nsIRDFLiteral);
  690.       if (target){
  691.         var url = target.Value;
  692.         openUILink(url,event);
  693.       }
  694.     }
  695.     else if (aType == "Folder" || aType == "Livemark" || aType == "PersonalToolbarFolder"){
  696.       this.updatedSelection = true;
  697.       this.bkmksTree.tree.view.selection.clearSelection();
  698.       this.updatedSelection = false;
  699.       this.bkmksTree.selectResource(resource);
  700.       var index = this.bkmksTree.treeBuilder.getIndexOfResource(resource);
  701.       if (!this.bkmksTree.tree.view.isContainerOpen(index))
  702.         this.bkmksTree.tree.view.toggleOpenState(index);
  703.       //AlbumViewUtils.refreshDisplay();
  704.     }
  705.   }
  706. }
  707. var ThumbViewUtils = {
  708.   displayRoot : null,
  709.   displayView : null,
  710.   view : null,
  711.   initDisplay : function(){
  712.     ThumbViewUtils.displayView = ThumbView;
  713.     BookmarksPreviewUtils.utils = ThumbViewUtils;
  714.     document.getElementById('thumbsSize').removeAttribute("disabled");
  715.     //ThumbView.init();
  716.     this.refreshDisplay(true);
  717.   },
  718.   uninit : function(){
  719.     this.initiated = false;
  720.     document.getElementById('thumbsSize').setAttribute("disabled","true");
  721.   },
  722.   onResize : function(event){
  723.     ThumbView.onResize(event);
  724.   },
  725.   refreshDisplay : function(aForceRefresh){
  726.     var bkmks=[];
  727.     this.initiated = true;
  728.     BookmarksPreviewUtils.getBookmarkImages(bkmks);
  729.     ThumbView.load(bkmks);
  730.   },
  731.   updatePreview : function(aURI){
  732.     aURI = aURI.QueryInterface(Components.interfaces.nsIURI);
  733.     ThumbView.updateThumbnail(aURI.spec);
  734.   },
  735.   updateNodeTitle : function(aNode, aPrevVal, aNewVal){
  736.     ThumbView.updateNodeTitle(aNode,aPrevVal,aNewVal);
  737.   },
  738.   back : function(){BookmarksPreviewUtils.back();},
  739.   forward : function(){BookmarksPreviewUtils.forward();},
  740.   getBookmarkImages : BookmarksPreviewUtils.getBookmarkImages,
  741.   _getNextTarget : function(cIndex,rIndex){
  742.     if (cIndex>rIndex+1){
  743.       var max = ThumbViewUtils.view.rowCount, level = ThumbViewUtils.view.getLevel(cIndex);
  744.       var nextTarget = 0;//rIndex==-1?-1:0;
  745.       for (var i = rIndex+1;i<cIndex;i++){
  746.         if (ThumbViewUtils.view.getLevel(i)==level &&
  747.            !ThumbViewUtils.view.isSeparator(i))
  748.           nextTarget++;
  749.       }
  750.       return nextTarget;
  751.     }
  752.     return 0;
  753.   },
  754.   selectItem : function(item, event){
  755.     //dump("thumbviewutils selectitem: "+item+"\n");
  756.     //ThumbViewUtils.updatedSelection = true;
  757.     //BookmarksPreviewUtils.bkmksTree.tree.view.selection.clearSelection();
  758.     //BookmarksPreviewUtils.bkmksTree.selectResource(item.node);
  759.     //ThumbViewUtils.updatedSelection = false;
  760.   },
  761.   performAction : function(item, event){
  762.     //dump("thumbviewutils.performaction\n");
  763.     var resource = item.node;
  764.     var aType = BookmarksUtils.resolveType(resource);
  765.     if (aType == "Bookmark"){
  766.       var target = BMDS.GetTarget(resource, RDF.GetResource("http://home.netscape.com/NC-rdf#URL"), true);
  767.       target = target.QueryInterface(Components.interfaces.nsIRDFLiteral);
  768.       if (target){
  769.         var url = target.Value;
  770.         openUILink(url,event);
  771.       }
  772.     }
  773.     else if (aType == "Folder" || aType == "Livemark" || aType == "PersonalToolbarFolder"){
  774.  
  775.       BookmarksPreviewUtils.bkmksTree.selectResource(resource);
  776.     }
  777.   },
  778.   removeItem : function(item, event){
  779.     var resource = item.node;
  780.     var parent = BMDS.getParent(resource);
  781.     var selection = BookmarksUtils.getSelectionFromResource(resource, parent);
  782.     BookmarksCommand.deleteBookmark(selection);
  783.     //dump("remove item refresh display\n");
  784.     ThumbViewUtils.refreshDisplay();
  785.   },
  786.   isSorted : function(){
  787.     return BookmarksPreviewUtils.sortChangedObserver.isSorted;
  788.   }
  789. }
  790. window.addEventListener('load',BookmarksPreviewUtils.init,false);
  791. window.addEventListener('unload',BookmarksPreviewUtils.uninit,false);
  792.